package cn.mengfly.testnrz.im.server.cocurrent;

import com.google.common.util.concurrent.*;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Mengfly
 */
public class CallbackTaskScheduler extends Thread {
    private final ConcurrentLinkedDeque<CallBackTask<?>> executeTaskQueue = new ConcurrentLinkedDeque<>();

    private long sleepTime = 200;

    private final ExecutorService jPool = Executors.newCachedThreadPool();
    private final ListeningExecutorService gPool = MoreExecutors.listeningDecorator(jPool);

    private static final CallbackTaskScheduler INSTANCE = new CallbackTaskScheduler();

    public static <R> void add(CallBackTask<R> executeTask) {
        INSTANCE.executeTaskQueue.add(executeTask);
    }

    public void setSleepTime(long sleepTime) {
        this.sleepTime = sleepTime;
    }

    private CallbackTaskScheduler() {
        this.start();
    }

    @Override
    public void run() {
        while (true) {
            handleTask();
            threadSleep(sleepTime);
        }
    }

    private void threadSleep(long time) {
        try {
            sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void handleTask() {
        try {
            while (executeTaskQueue.peek() != null) {
                handleTask(executeTaskQueue.poll());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private <R> void handleTask(final CallBackTask<R> executeTask) {
        ListenableFuture<R> future = gPool.submit(executeTask::execute);
        Futures.addCallback(future, new FutureCallback<R>() {
            @Override
            public void onSuccess(@Nullable R result) {
                executeTask.onBack(result);
            }

            @Override
            public void onFailure(Throwable throwable) {
                executeTask.onException(throwable);
            }
        }, gPool);
    }
}
